﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Web.Mvc;
using System.Runtime.Serialization;
using System.Text;
using Newtonsoft.Json;

namespace EditAnyString.Web.DataTable
{
	[Serializable]
	public class DataTableDictionary<K, V> : ISerializable
	{
		Dictionary<K, V> dict = new Dictionary<K, V>();

		public DataTableDictionary() { }

		protected DataTableDictionary( SerializationInfo info, StreamingContext context )
		{
			throw new NotImplementedException();
		}

		public void GetObjectData( SerializationInfo info, StreamingContext context )
		{
			foreach( K key in dict.Keys )
			{
				info.AddValue( key.ToString(), dict[ key ] );
			}
		}

		public void Add( K key, V value )
		{
			dict.Add( key, value );
		}

		public V this[ K index ]
		{
			set { dict[ index ] = value; }
			get { return dict[ index ]; }
		}
	}

	public class DataTableResult : ActionResult {

		[DataContract]
		public class ResultData
		{

			/// <summary>
			/// An unaltered copy of sEcho sent from the client side. 
			/// This parameter will change with each draw (it is basically a draw count) - 
			/// so it is important that this is implemented. Note that it strongly recommended 
			/// for security reasons that you 'cast' this parameter to an integer 
			/// in order to prevent Cross Site Scripting (XSS) attacks.
			/// </summary>        
			[DataMember( Name = "sEcho" )]
			public string sEcho { get; set; }

			/// <summary>
			/// Total records, before filtering (i.e. the total number of records in the database)
			/// </summary>
			[DataMember( Name = "iTotalRecords" )]
			public int iTotalRecords { get; set; }

			/// <summary>
			/// Total records, after filtering (i.e. the total number of records after filtering has been applied - 
			/// not just the number of records being returned in this result set)
			/// </summary>
			[DataMember( Name = "iTotalDisplayRecords" )]
			public int iTotalDisplayRecords { get; set; }

			/// <summary>
			/// Optional - this is a string of column names, comma separated (used in combination with sName) 
			/// which will allow DataTables to reorder data on the client-side if required for display
			/// </summary>
			[DataMember( Name = "sColumns" )]
			public string sColumns { get; set; }

			/// <summary>
			/// The data in a 2D array
			/// Fill this structure with the plain table data
			/// represented as string.
			/// </summary>
			[DataMember( Name = "aaData" )]
			public List<Dictionary<string, string>> aaData { get; set; }
		}

		private ResultData _result;

		public List<Dictionary<string, string>> aaData
		{
			get { return _result.aaData; }
		}

        public Encoding ContentEncoding { get; set; }

        public string ContentType { get; set; }

        public JsonRequestBehavior JsonRequestBehavior { get; set; }

		public DataTableResult( string sEcho, int iTotalRecords, int iTotalDisplayRecords )
		{
            this.JsonRequestBehavior = JsonRequestBehavior.DenyGet;
			_result = new ResultData();
			_result.sEcho = sEcho;
			_result.iTotalRecords = iTotalRecords;
			_result.iTotalDisplayRecords = iTotalDisplayRecords;
			_result.aaData = new List<Dictionary<string, string>>();
			ContentEncoding = Encoding.UTF8;
        }

		public DataTableResult( DataTableModel dataTable, int iTotalRecords, int iTotalDisplayRecords )
            : this(dataTable.sEcho, iTotalRecords, iTotalDisplayRecords ) {
        }

        public override void ExecuteResult(ControllerContext context) {
            if (context == null) {
                throw new ArgumentNullException("context");
            }
            if ((this.JsonRequestBehavior == JsonRequestBehavior.DenyGet) &&
                string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) {
                throw new InvalidOperationException("Get not allowed");
            }
            HttpResponseBase response = context.HttpContext.Response;
            if (!string.IsNullOrEmpty(this.ContentType)) {
                response.ContentType = this.ContentType;
            } else {
                response.ContentType = "application/json";
            }
            if (this.ContentEncoding != null) {
                response.ContentEncoding = this.ContentEncoding;
            }

			string json = JsonConvert.SerializeObject( _result, Formatting.Indented );
			response.Write( json );
        }
	}
}